/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.pearreview.ui.slidebox;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceMotionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.EventListener;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.TransferHandler;

import com.pearreview.ui.CheckedLabel;
import com.pearreview.ui.FormLabel;
import com.pearreview.ui.SmallPearPanel;
import com.pearreview.util.DoubleClickMouseAdapter;
import com.pearreview.application.Messages;

/**
 * A generic box for displaying complex content with possibility to slide
 * it up, to hide the content and slide it down to show the content.
 * 
 * @author Dimitrij Pankratz, Anton Musichin
 *
 * @param <T>
 */
public class SlideBox<T> extends JPanel implements ActionListener, 
		Transferable, DragGestureListener {

	private static final long serialVersionUID = 4473538113264155940L;
	public SmallPearPanel containerTop = new SmallPearPanel();
	protected JPanel containerBottom = new JPanel();
	private boolean slideDown = true;
	private boolean slideLock = false;
	protected boolean fading = false;
	
	protected int minWidth = 250;
	protected int maxWidth = 3000;
	protected int maxHeightTop = 25; 
	protected int heightContainer = maxHeightTop + 5; //5 points for border
	
	protected int slidedHeight = 200;
	
	protected float alpha = 1.0f;
	protected Timer timer;
	protected int animationDuration = 500;
	protected long animationStartTime;
	protected BufferedImage buttonImage = null;
	protected final JButton deleteBtn = new JButton();
	protected final JButton editBtn = new JButton();
	protected final SlideOpenButton slideBtn = new SlideOpenButton();
	private Action deleteAction;
	protected Action editAction;
	private FormLabel captionLabel;
	protected CheckedLabel checkLabel = new CheckedLabel();
	protected T element;	
	
	private DragSource dragSource;
	private boolean dragEnabled = false;
	
	private RemoveConfirmer removeConfirmer;
	
	//top layout
	private GroupLayout layout;
	
	public T getElement() {
		return element;
	}
	
	public SlideBox(T element, Action deleteAction, Action editAction) {
		super();
		
		this.element = element;
		this.deleteAction = deleteAction;
		this.editAction = editAction;
		
		setOpaque(false);
		timer = new Timer(30, (ActionListener) this);
		
		setPreferredSize(new Dimension(250,heightContainer));
		setMaximumSize(new Dimension(3000,heightContainer));
		setMinimumSize(new Dimension(250,heightContainer));
		setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		
		initComponents();
			
		this.setTransferHandler(new DragAndDropTransferHandler());
		
		dragSource = new DragSource();
		dragSource.createDefaultDragGestureRecognizer(this, 
				DnDConstants.ACTION_COPY_OR_MOVE, 
				this);
		dragEnabled = true;
	}
	
	public void setRemoveConfirmer(RemoveConfirmer newRemoveConfirmer) {
		removeConfirmer = newRemoveConfirmer;
	}
	
	public RemoveConfirmer getRemoveConfirmer(RemoveConfirmer confirmer) {
		return removeConfirmer;
	}
	
	public void setFocus(boolean hasFocus) {
		captionLabel.setFocus(hasFocus);
	}
	
	protected void initComponents() {
		containerTop.setPreferredSize(new Dimension(minWidth,maxHeightTop));
		containerTop.setMaximumSize(new Dimension(maxWidth,maxHeightTop));
		containerTop.setMinimumSize(new Dimension(minWidth,maxHeightTop));
		containerTop.setSize(new Dimension(minWidth,maxHeightTop));
		containerTop.setBorder(BorderFactory.createMatteBorder(
				1, 1, 1, 1, new Color(0x828790)));
		slideBtn.setUI(new SlideOpenButtonUI());
		slideBtn.setFocusable(false);
		slideBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (slideDown) {
					slideDown(slidedHeight);
				} else {
					slideUp(0);
				}
			}
		});
		
		
		//---- this ----
		addMouseListener(new DoubleClickMouseAdapter() {
			private static final long serialVersionUID = 1981700082474600901L;
			@Override
			public void mouseDoubleClicked(MouseEvent e) {
				if (slideDown) {
					slideDown(slidedHeight);
				} else {
					slideUp(0);
				}
			}
		});
		
		
		//---- deleteBtn ----
		deleteBtn.setOpaque(false);
		deleteBtn.setUI(new CloseButtonSlideBoxUI());
		deleteBtn.setPreferredSize(new Dimension(12, 12));
		deleteBtn.setMinimumSize(new Dimension(12, 12));
		deleteBtn.setToolTipText(Messages.getString(
				"PearReview.Moderator.delete_btn"));
		deleteBtn.addActionListener(this);
		deleteBtn.setFocusable(false);
		
		//---- editBtn ----
		editBtn.setMargin(new Insets(0,0,0,0));
		editBtn.setPreferredSize(new Dimension(16, 16));
		editBtn.setMinimumSize(new Dimension(16, 16));
		editBtn.setToolTipText(Messages.getString(
			"PearReview.Moderator.edit_btn"));
		editBtn.setUI(new EditButtonSlideBoxUI());
		editBtn.setOpaque(false);
		editBtn.setFocusable(false);
		editBtn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		editBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit();
			}
		});
		
		//---- captionLabel ----
		captionLabel = new FormLabel(getCaption());
		captionLabel.setFont(new Font("Tahoma", Font.PLAIN, 12));
		captionLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
		
		
		layout = new GroupLayout(containerTop);
		containerTop.setLayout(layout);
		
		checkLabel.setVisible(false);
		
		layout.setHorizontalGroup(
			layout.createSequentialGroup()
				.addGap(10, 10, 10)
				.addComponent(slideBtn, 
						GroupLayout.PREFERRED_SIZE, 
						GroupLayout.DEFAULT_SIZE, 
						GroupLayout.PREFERRED_SIZE)
				.addComponent(captionLabel, 
						20, 
						GroupLayout.DEFAULT_SIZE, 
						Short.MAX_VALUE)
				.addGap(10, 10, 10)
				.addComponent(checkLabel, 
						16, 
						GroupLayout.PREFERRED_SIZE, 
						GroupLayout.PREFERRED_SIZE)
				.addGap(10, 10, 10)
				.addComponent(editBtn, 
						GroupLayout.PREFERRED_SIZE, 
						GroupLayout.DEFAULT_SIZE, 
						GroupLayout.PREFERRED_SIZE)
				.addGap(10, 10, 10)
				.addComponent(deleteBtn, 
						GroupLayout.PREFERRED_SIZE, 
						GroupLayout.DEFAULT_SIZE, 
						GroupLayout.PREFERRED_SIZE)
				.addGap(10, 10, 10)
		);
		
		layout.setVerticalGroup(
			layout.createSequentialGroup()
			.addGap(4)
				.addGroup(layout.createParallelGroup(
						GroupLayout.Alignment.CENTER)
					.addComponent(slideBtn, 
							GroupLayout.PREFERRED_SIZE, 
							GroupLayout.DEFAULT_SIZE, 
							GroupLayout.PREFERRED_SIZE)
					.addComponent(captionLabel, 
							GroupLayout.PREFERRED_SIZE, 
							GroupLayout.DEFAULT_SIZE, 
							GroupLayout.PREFERRED_SIZE)
					.addComponent(checkLabel, 
							GroupLayout.PREFERRED_SIZE, 
							GroupLayout.DEFAULT_SIZE, 
							GroupLayout.PREFERRED_SIZE)
					.addComponent(editBtn, 
							GroupLayout.PREFERRED_SIZE, 
							GroupLayout.DEFAULT_SIZE, 
							GroupLayout.PREFERRED_SIZE)
					.addComponent(deleteBtn, 
							GroupLayout.PREFERRED_SIZE,
							GroupLayout.DEFAULT_SIZE, 
							GroupLayout.PREFERRED_SIZE)
		));
		
		
		add(containerTop);
		
		containerBottom.setPreferredSize(new Dimension(minWidth,0));
		containerBottom.setMaximumSize(new Dimension(maxWidth,0));
		containerBottom.setMinimumSize(new Dimension(minWidth,0));
		containerBottom.setBackground(new Color(0xffffff));
		
		initContent(containerBottom);
		
		add(containerBottom);
		
		setBorderNormal();
		
		containerTop.validate();
		validate();
	}
	
	/**
	 * Notify edit action, that this component should be edit.
	 */
	public void edit() {
		editAction.actionPerformed(new ActionEvent(element, 
				ActionEvent.ACTION_PERFORMED, "edit"));
	}
	
	/**
	 * Deletes this box
	 */
	public void delete() {
		ActionEvent ac = new ActionEvent(deleteBtn, 
				ActionEvent.ACTION_PERFORMED, "delete");
		actionPerformed(ac);
	}
	
	/**
	 * Display selected border.
	 */
	protected void setBorderNormal() {
		containerBottom.setBorder(BorderFactory.createMatteBorder(
				0, 1, 1, 1, new Color(0x828790)));
		containerTop.setBorder(BorderFactory.createMatteBorder(
				1, 1, 1, 1, new Color(0x828790)));
	}
	
	/**
	 * Dispaly normal border.
	 */
	protected void setBorderSelected() {
		containerBottom.setBorder(BorderFactory.createMatteBorder(
				0, 1, 1, 1, new Color(0x666666)));
		containerTop.setBorder(BorderFactory.createMatteBorder(
				1, 1, 1, 1, new Color(0x666666)));
	}
	
	/**
	 * Makes the box display visual as selected if true. Otherwise displays
	 * it normaly.
	 * 
	 * @param selected
	 */
	public void setSelected(boolean selected) {
		containerTop.revertColor(selected);
		if (selected) {
			setBorderSelected();
		} else {
			setBorderNormal();
		}
	}
	
	/**
	 * Returns the preferred slide height.
	 * 
	 * @return
	 */
	public int getSlideHeight() {
		return slidedHeight;
	}
	
	/**
	 * Returns true if, the box is opened.
	 * 
	 * @return
	 */
	public boolean isOpened() {
		return !this.slideDown;
	}
	
	/**
	 * Updates the content of the box.
	 */
	public void updateBox() {
		captionLabel.setText(getCaption());
		containerBottom.removeAll();
		initContent(containerBottom);
	}
	
	/**
	 * Sets the given element in order to display it.
	 * 
	 * @param element
	 */
	public void setElement(T element) {
		this.element = element;
	}

	public void slideDown(final int endHeight) {
		slideDown(endHeight, false);
	}
	
	/**
	 * Opens the content of the box, to the given height.
	 * 
	 * @param endHeight
	 * @param fast
	 */
	public void slideDown(final int endHeight, final boolean fast) {
		
		final boolean saveDragState = this.dragEnabled;
		
		if (!slideLock && slideDown) {
			slideLock = true;
			setDragEnabled(false);
			slideBtn.setOpenState(true);
			slideDown = false;
			
			final int endHeightContainer = 
				containerBottom.getHeight() + endHeight;
			final int endHeightSlideBox = 
				SlideBox.this.getHeight() + endHeight;
			
			new Thread() {
				{
					start();
				}
	
				public void run() {
					
					while (containerBottom.getHeight() < endHeight) {
						
						int x = 10;
						if (fast)
							x = 50;
						
						containerBottom.setSize(containerTop.getWidth(), 
								containerBottom.getHeight()+x);
						SlideBox.this.setSize(SlideBox.this.getWidth(), 
								SlideBox.this.getHeight()+x);
							
						containerBottom.setPreferredSize(new Dimension(
								minWidth, containerBottom.getHeight()+x));
						containerBottom.setMinimumSize(new Dimension(minWidth,
								containerBottom.getHeight()+x));
						containerBottom.setMaximumSize(new Dimension(maxWidth,
								containerBottom.getHeight()+x));
							
						SlideBox.this.setPreferredSize(new Dimension(minWidth,
								SlideBox.this.getHeight()+x));
						SlideBox.this.setMinimumSize(new Dimension(minWidth,
								SlideBox.this.getHeight()+x));
						SlideBox.this.setMaximumSize(new Dimension(maxWidth,
								SlideBox.this.getHeight()+x));
							
						SlideBox.this.validate();
						if (SlideBox.this.getParent() != null) {
							SlideBox.this.getParent().validate();
							SlideBox.this.getParent().getParent().validate();
							SlideBox.this.getParent().getParent().getParent()
									.validate();
						}
						try {
							Thread.sleep(0, 1);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					slideLock = false;
					
					containerBottom.setSize(containerTop.getWidth(), 
							endHeightContainer);
					SlideBox.this.setSize(SlideBox.this.getWidth(), 
							endHeightSlideBox);
						
					containerBottom.setPreferredSize(new Dimension(
							minWidth,endHeightContainer));
					containerBottom.setMinimumSize(new Dimension(
							minWidth,endHeightContainer));
					containerBottom.setMaximumSize(new Dimension(
							maxWidth,endHeightContainer));
						
					SlideBox.this.setPreferredSize(new Dimension(
							minWidth,endHeightSlideBox));
					SlideBox.this.setMinimumSize(new Dimension(
							minWidth,endHeightSlideBox));
					SlideBox.this.setMaximumSize(new Dimension(
							maxWidth,endHeightSlideBox));
						
					SlideBox.this.validate();
					if (SlideBox.this.getParent() != null) {
						SlideBox.this.getParent().validate();
						SlideBox.this.getParent().getParent().validate();
						SlideBox.this.getParent().getParent().getParent()
								.validate();
						SlideBox.this.getParent().getParent().getParent()
								.getParent().validate();
					}
					setDragEnabled(saveDragState);
					
				}
			};
		}
	}
	
	public void slideUp(final int endHeight) {
		slideUp(endHeight, false);
	}
	
	/**
	 * Closes the box to the given size.
	 * 
	 * @param endHeight
	 * @param fast
	 */
	public void slideUp(final int endHeight, final boolean fast) {
		final boolean saveDragState = this.dragEnabled;
		
		if (!slideLock && !slideDown) {
			slideLock = true;
			setDragEnabled(false);
			slideBtn.setOpenState(false);
			slideDown = true;
			
			final int endHeightContainer = endHeight;
			final int endHeightSlideBox = heightContainer;
			
			new Thread() {
				{
					start();
				}
	
				public void run() {
					
					while (containerBottom.getHeight() > endHeight) {
						int x = 10;
						if (fast)
							x = 50;
						
						containerBottom.setSize(containerTop.getWidth(), 
								containerBottom.getHeight()-x);
						SlideBox.this.setSize(SlideBox.this.getWidth(), 
								SlideBox.this.getHeight()-x);
							
						containerBottom.setPreferredSize(new Dimension(
								minWidth,containerBottom.getHeight()-x));
						containerBottom.setMinimumSize(new Dimension(
								minWidth,containerBottom.getHeight()-x));
						containerBottom.setMaximumSize(new Dimension(
								maxWidth,containerBottom.getHeight()-x));
							
						SlideBox.this.setPreferredSize(new Dimension(
								minWidth,SlideBox.this.getHeight()-x));
						SlideBox.this.setMinimumSize(new Dimension(
								minWidth,SlideBox.this.getHeight()-x));
						SlideBox.this.setMaximumSize(new Dimension(
								maxWidth,SlideBox.this.getHeight()-x));
							
						SlideBox.this.validate();
						if (SlideBox.this.getParent() != null) {
							SlideBox.this.getParent().validate();
							SlideBox.this.getParent().getParent().validate();
							SlideBox.this.getParent().getParent().getParent()
									.validate();
						}
						try {
							Thread.sleep(0, 1);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					slideLock = false;
					
					containerBottom.setSize(containerTop.getWidth(), 
							endHeightContainer);
					SlideBox.this.setSize(SlideBox.this.getWidth(), 
							endHeightSlideBox);
						
					containerBottom.setPreferredSize(new Dimension(
							minWidth,endHeightContainer));
					containerBottom.setMinimumSize(new Dimension(
							minWidth,endHeightContainer));
					containerBottom.setMaximumSize(new Dimension(
							maxWidth,endHeightContainer));
						
					SlideBox.this.setPreferredSize(new Dimension(
							minWidth,endHeightSlideBox));
					SlideBox.this.setMinimumSize(new Dimension(
							minWidth,endHeightSlideBox));
					SlideBox.this.setMaximumSize(new Dimension(
							maxWidth,endHeightSlideBox));
						
					SlideBox.this.validate();
					if (SlideBox.this.getParent() != null) {
						SlideBox.this.getParent().validate();
						SlideBox.this.getParent().getParent().validate();
						SlideBox.this.getParent().getParent().getParent()
								.validate();
					}
					setDragEnabled(saveDragState);
				}
			};
		}
	}
	
	
	public void paint(Graphics g) {
		if (fading) {
			// Create an image for the button graphics if necessary
			if (buttonImage == null || buttonImage.getWidth() != getWidth() ||
					buttonImage.getHeight() != getHeight()) {
				buttonImage = getGraphicsConfiguration().
						createCompatibleImage(getWidth(), getHeight()-5);
			}
			Graphics gButton = buttonImage.getGraphics();
			gButton.setClip(g.getClip());
			
			//  Have the superclass render the button for us
			super.paint(gButton);
			
			// Make the graphics object sent to this paint() method translucent
			Graphics2D g2d  = (Graphics2D)g;
			AlphaComposite newComposite = 
				AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
			g2d.setComposite(newComposite);
			
			// Copy the button's image to the destination graphics, 
			//translucently
			g2d.drawImage(buttonImage, 0, 0, null);
		} else {
			super.paint(g);
		}
	}
	
	public boolean canRemove() {
		if(removeConfirmer != null) {
			return removeConfirmer.canRemove(this);
		}
		return true;
	}

	/**
	 * This method receives both click events (which start and stop the
	 * animation) and Timer events (which animate the alpha of the box).
	 */
	public void actionPerformed(ActionEvent ae) {
		if (ae.getSource().equals(deleteBtn)) {
			// button click
			if (!timer.isRunning()) {
				
				if(!canRemove()) {
					return;
				}

				//no sliding while deleting
				slideLock = true;
				//no drag while deleting
				setDragEnabled(false);
				//no editing while deleting
				editBtn.setEnabled(false);
				//editBtn.setVisible(false);
				checkLabel.setEnabled(false);
				fading = true;
				animationStartTime = System.nanoTime() / 1000000;
				timer.start();
			}
			
		} else {
			// timer event
			// calculate the elapsed fraction
			long currentTime = System.nanoTime() / 1000000;
			long totalTime = currentTime - animationStartTime;
			if (totalTime > animationDuration) {
				//animationStartTime = currentTime;
				timer.stop();
				deleteAction.actionPerformed(new ActionEvent(
						this, 1, "Delete"));
			}
			float fraction = (float)totalTime / animationDuration;
			fraction = Math.min(1.0f, fraction);
			// This calculation will cause alpha to go from 1 to 0 and 
			//back to 1 as the fraction goes from 0 to 1
			alpha = Math.abs(1 - (fraction));
			// redisplay our button with its new alpha value
			repaint();
		}
	}
	
	/**
	 * Should be overridden by a child to display a heading.
	 * 
	 * @return
	 */
	protected String getCaption() {
		return new String();
	}
	
	/**
	 * Should be overridden by a child to display the content of the box.
	 *  
	 * @param containerBottom
	 */
	protected void initContent(JPanel containerBottom) {
	}
	
	/**
	 * 
	 * @return
	 */
	public static DataFlavor getDataFlavor() {
		try {
			return new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + 
					";class=" + SlideBox.class.getName());
		} catch(ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public Object getTransferData(DataFlavor flavor)
			throws UnsupportedFlavorException, IOException {
		DataFlavor thisFlavor = getDataFlavor();
		
		if (thisFlavor != null && flavor.equals(thisFlavor)) {
			return SlideBox.this;
		}

		return null;
	}

	@Override
	public DataFlavor[] getTransferDataFlavors() {
		DataFlavor[] flavors = {getDataFlavor()};
		return flavors;
	}

	@Override
	public boolean isDataFlavorSupported(DataFlavor flavor) {		
		DataFlavor[] flavors = {null};
		flavors[0] = getDataFlavor();

		for (DataFlavor f : flavors) {
			if (f.equals(flavor)) {
				return true;
			}
		}

		return false;
	}
	
	/**
	 * 
	 *
	 */
	private class DragAndDropTransferHandler extends TransferHandler 
			implements DragSourceMotionListener {
		
		private static final long serialVersionUID = 6443686319313632645L;

		public DragAndDropTransferHandler() {
			super();
		}
		@Override()
		public Transferable createTransferable(JComponent c) {
			
			if(c instanceof SlideBox<?>) {
				Transferable tip = (SlideBox<?>) c;
				return tip;
			}

			return null;
		}
		@Override
		public void dragMouseMoved(DragSourceDragEvent arg0) {			
		}
		
		@Override()
		public int getSourceActions(JComponent c) {
			if(c instanceof SlideBox<?>) {
				return TransferHandler.COPY;
			}			
			return TransferHandler.NONE;
		}
		@Override
		public boolean canImport(JComponent comp, 
				DataFlavor[] transferFlavors) {
			return true;
		}
	}

	@Override
	public void dragGestureRecognized(DragGestureEvent evt) {
		if(!dragEnabled)
			return;
		JComponent c = SlideBox.this;
		TransferHandler handler = c.getTransferHandler();
		handler.exportAsDrag(c, evt.getTriggerEvent(), TransferHandler.COPY);
		
	}
	
	/**
	 * If true allows to drag the box, otherwise not.
	 * 
	 * @param enabled
	 */
	public void setDragEnabled(boolean enabled) {
		dragEnabled = enabled;
	}
	
	/**
	 * If true, allows to delete the box, otherwise not.
	 * 
	 * @param enabled
	 */
	public void setDeleteEnabled(boolean enabled) {
		this.deleteBtn.setEnabled(enabled);
		this.deleteBtn.setVisible(enabled);
	}
	
	/**
	 * If true allows to edit the box, otherwise not.
	 * 
	 * @param enabled
	 */
	public void setEditEnabled(boolean enabled) {
		this.editBtn.setEnabled(enabled);
		this.editBtn.setVisible(enabled);
	}
	
	/**
	 * If true allows to un-check box, otherwise not.
	 * 
	 * @param enabled
	 */
	public void setCheckEnabled(boolean enabled) {
		this.checkLabel.setEnabled(enabled);
		this.checkLabel.setVisible(enabled);
	}
	
	public boolean isCheckEnabled() {
		return checkLabel.isEnabled() && checkLabel.isVisible();
	}
	
	public boolean isEditEnabled() {
		return editBtn.isEnabled() && editBtn.isVisible();
	}
	
	public boolean isDeleteEnabled() {
		return deleteBtn.isEnabled() && deleteBtn.isVisible();
	}
	
	public interface RemoveConfirmer extends EventListener {
		public boolean canRemove(SlideBox<?> box);
	}
}
